home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / vol6n16.arc / KBX.ASM next >
Assembly Source File  |  1987-08-29  |  30KB  |  589 lines

  1. ;KBX.COM for the IBM Personal Computer - 1987 by Jeff Prosise
  2. ;
  3. kb_data       equ 60h                       ;keyboard data port
  4. kb_ctrl       equ 61h                       ;keyboard control port
  5. eoi           equ 20h                       ;8259 EOI value
  6. int_ctrl      equ 20h                       ;8259 port address
  7. ;
  8. bios_data     segment at 40h                ;BIOS data area
  9.               org 17h
  10. kb_status     db ?                          ;keyboard status byte
  11.               org 1Ah
  12. buffer_head   dw ?                          ;pointer to keyboard buffer head
  13. buffer_tail   dw ?                          ;pointer to keyboard buffer tail
  14.               org 80h
  15. buffer_start  dw ?                          ;starting keyboard buffer address
  16. buffer_end    dw ?                          ;ending keyboard buffer address
  17. bios_data     ends
  18. ;
  19. code          segment para public 'code'    ;code segment
  20.               assume cs:code
  21.               org 100h
  22. begin:        jmp initialize                ;goto initialization code
  23. ;
  24. copyright          db 'Copyright 1987 Ziff-Davis Publishing Co.',1Ah
  25. enable_values      db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
  26. screen_buffer      dw offset initialize     ;pointer to screen buffer
  27. aux_shift          db 0                     ;auxiliary keyboard status byte
  28. old_shift          db 0                     ;storage for shift status
  29. window_status      db 0                     ;window display status
  30. adapter            db 2                     ;0 = MDA, 1 = CGA, 2 = EGA
  31. video_segment      dw 0B800h                ;default video segment
  32. border_attr        db 2Fh                   ;window border attribute
  33. text_attr          db 1Bh                   ;window border attribute
  34. cursor_mode        dw 0607h                 ;default cursor shape
  35. cursor_position    dw ?                     ;saved cursor position
  36. video_page         db ?                     ;saved video page number
  37. video_offset       dw ?                     ;starting window offset address
  38. addr_6845          dw ?                     ;port address of CRTC
  39. ibm                db 'IBM'                 ;EGA ASCII signature
  40. old9h              label dword
  41. old9h_vector       dw 2 dup (?)             ;storage for interrupt 9 vector
  42. ;
  43. fill_parms    dw 1,030Fh,12
  44.               dw 2,050Fh,12
  45.               dw 2,070Fh,12
  46.               dw 2,090Fh,10
  47.               dw 17,0537h,4
  48.               dw 0,0737h,4
  49.               dw 0,0937h,3
  50. ;
  51. def_table     db 0,'1234567890-=',0
  52.               db 0,'QWERTYUIOP[]',0
  53.               db 0,'ASDFGHJKL;',39,96
  54.               db 0,0,'ZXCVBNM,./'
  55.               db 17 dup (0)
  56.               db '789-456+123',0,0
  57. ;
  58. scr_table     db 0,127,128,129,130,131,132,133,134,135,136,137,138,0
  59.               db 0,139,140,141,142,143,144,145,146,147,148,149,150,0
  60.               db 0,151,152,153,154,155,156,157,158,159,160,161,162
  61.               db 0,0,163,164,165,166,167,168,0,0,0,0
  62.               db 17 dup (0)
  63.               db 201,203,187,205,204,206,185,186,200,202,188,0,0
  64. ;
  65. num_table     db 0,169,170,171,172,173,174,175,176,177,178,219,220,0
  66.               db 0,221,222,223,224,225,226,227,228,229,230,231,232,0
  67.               db 0,233,234,235,236,237,238,239,240,241,242,243,244
  68.               db 0,0,245,246,247,248,249,250,251,252,253,254
  69.               db 17 dup (0)
  70.               db 218,194,191,196,195,197,180,179,192,193,217,0,0
  71. ;
  72. ;------------------------------------------------------------------------------
  73. ;Interrupt 9 handler.  Execution comes here when a key is pressed or released.
  74. ;------------------------------------------------------------------------------
  75. new9h         proc near
  76.               sti                           ;set interrupt enable flag
  77.               push ax                       ;save AX
  78.               in al,kb_data                 ;get scan code from keyboard
  79.               cmp al,69                     ;NumLock key pressed?
  80.               je numlock_down               ;yes, then branch
  81.               cmp al,69+128                 ;NumLock key released?
  82.               je numlock_up                 ;yes, then branch
  83.               cmp al,70                     ;ScrLock key pressed?
  84.               je scrlock_down               ;yes, then branch
  85.               cmp al,70+128                 ;ScrLock key released?
  86.               je scrlock_up                 ;yes, then branch
  87.               cmp al,57                     ;spacebar pressed?
  88.               je spacebar                   ;yes, then branch
  89.               cmp aux_shift,0               ;NumLock or ScrLock depressed?
  90.               je exit                       ;no, then exit
  91.               jmp newkey                    ;yes, then branch
  92. exit:         pop ax                        ;restore AX
  93.               jmp old9h                     ;goto old interrupt handler
  94. ;
  95. ;The NumLock key was pressed.  Toggle NumLock state or set shift bit.
  96. ;
  97. numlock_down: call get_status               ;get main shift status byte
  98.               test al,12                    ;is either Ctrl or Alt pressed?
  99.               jnz exit                      ;yes, then goto normal handler
  100.               push ax                       ;save shift code
  101.               call reset_kb                 ;reset the keyboard
  102.               pop ax                        ;retrieve shift code
  103.               test al,3                     ;is either Shift key depressed?
  104.               jnz numlock1                  ;yes, then branch
  105.               or aux_shift,2                ;set NumLock shift bit
  106.               jmp end_int                   ;exit
  107. numlock1:     push ds                       ;save DS
  108.               mov ax,bios_data              ;point DS to BIOS data area
  109.               mov ds,ax
  110.               assume ds:bios_data
  111.               xor kb_status,32              ;toggle NumLock state
  112.               pop ds                        ;restore DS
  113.               assume ds:nothing
  114.               jmp end_int                   ;exit
  115. ;
  116. ;The NumLock key was released.  Clear the NumLock shift bit.
  117. ;
  118. numlock_up:   call reset_kb                 ;reset the keyboard
  119.               and aux_shift,253             ;clear shift bit
  120.               jmp end_int                   ;exit
  121. ;
  122. ;The ScrLock key was pressed.  Toggle ScrLock state or set shift bit.
  123. ;
  124. scrlock_down: call get_status               ;get main shift status byte
  125.               test al,12                    ;is either Ctrl or Alt pressed?
  126.               jnz exit                      ;yes, then goto normal handler
  127.               push ax                       ;save shift code
  128.               call reset_kb                 ;reset the keyboard
  129.               pop ax                        ;retrieve shift code
  130.               test al,3                     ;is either Shift key depressed?
  131.               jnz scrlock1                  ;yes, then branch
  132.               or aux_shift,1                ;set ScrLock shift bit
  133.               jmp end_int                   ;exit
  134. scrlock1:     push ds                       ;save DS
  135.               mov ax,bios_data              ;point DS to BIOS data area
  136.               mov ds,ax
  137.               assume ds:bios_data
  138.               xor kb_status,16              ;toggle ScrLock state
  139.               pop ds                        ;restore DS
  140.               assume ds:nothing
  141.               jmp end_int                   ;exit
  142. ;
  143. ;The ScrLock key was released.  Clear the ScrLock shift bit.
  144. ;
  145. scrlock_up:   call reset_kb                 ;reset the keyboard
  146.               and aux_shift,254             ;clear shift bit
  147. end_int:      mov al,eoi                    ;issue EOI to 8259 controller
  148.               out int_ctrl,al
  149.               pop ax                        ;clean up the stack
  150.               iret                          ;return from interrupt
  151. ;
  152. ;The spacebar was pressed.  Pop up the window if Alt is depressed.
  153. ;
  154. spacebar:     call get_status               ;get current shift status
  155.               test al,8                     ;is the Alt key depressed?
  156.               jz exit                       ;no, then exit to normal handler
  157.               call reset_kb                 ;yes, then reset keyboard
  158.               mov al,eoi                    ;issue end-of-interrupt signal
  159.               out int_ctrl,al
  160.               cmp window_status,0           ;is the window already up?
  161.               jne space1                    ;yes, then ignore keypress
  162.               push bx                       ;save BX
  163.               call kb_display               ;pop up keyboard display
  164.               pop bx                        ;restore BX
  165. space1:       pop ax                        ;clean up the stack
  166.               iret                          ;exit
  167. ;
  168. ;A key was pressed or released with NumLock or ScrLock held down.
  169. ;
  170. newkey:       push ax                       ;save scan code
  171.               call reset_kb                 ;reset keyboard
  172.               pop ax                        ;recover scan code
  173.               test al,80h                   ;is the high bit set?
  174.               jnz newkey3                   ;yes, then don't process it
  175.               push bx                       ;save BX
  176.               mov bx,offset num_table       ;point BX to NumLock key table
  177.               cmp aux_shift,1               ;ScrLock depressed?
  178.               jne newkey1                   ;no, then continue
  179.               mov bx,offset scr_table       ;yes, then adjust BX
  180. newkey1:      mov ah,al                     ;transfer scan code to AH
  181.               dec al                        ;set AL relative to zero base
  182.               xlat num_table                ;get ASCII code from table
  183.               or al,al                      ;is it zero?
  184.               je newkey2                    ;yes, then don't process this key
  185.               call insert_char              ;insert character into kb buffer
  186. newkey2:      pop bx                        ;restore BX register value
  187. newkey3:      mov al,eoi                    ;issue end-of-interrupt signal
  188.               out int_ctrl,al
  189.               pop ax                        ;restore AX and clean up the stack
  190.               iret
  191. new9h         endp
  192. ;
  193. ;------------------------------------------------------------------------------
  194. ;RESET_KB resets the keyboard.
  195. ;------------------------------------------------------------------------------
  196. reset_kb      proc near
  197.               in al,kb_ctrl                 ;get control port value
  198.               mov ah,al                     ;save it
  199.               or al,80h                     ;set high bit of control value
  200.               out kb_ctrl,al                ;send reset value
  201.               mov al,ah                     ;get original control value
  202.               out kb_ctrl,al                ;enable keyboard
  203.               ret                           ;done
  204. reset_kb      endp
  205. ;
  206. ;------------------------------------------------------------------------------
  207. ;GET_STATUS returns the main keyboard shift status byte in AL.
  208. ;------------------------------------------------------------------------------
  209. get_status    proc near
  210.               push ds                       ;save DS
  211.               mov ax,bios_data              ;point DS to BIOS data area
  212.               mov ds,ax
  213.               assume ds:bios_data
  214.               mov al,kb_status              ;get status byte in AL
  215.               pop ds                        ;restore DS
  216.               assume ds:nothing
  217.               ret                           ;exit
  218. get_status    endp
  219. ;
  220. ;------------------------------------------------------------------------------
  221. ;INSERT_CHAR inserts the character code in AX into the keyboard buffer.
  222. ;Entry:  AH,AL - scan code, ASCII code
  223. ;------------------------------------------------------------------------------
  224. insert_char   proc near
  225.               push dx                       ;save DX and DS
  226.               push ds
  227.               mov bx,bios_data              ;point DS to BIOS data area
  228.               mov ds,bx
  229.               assume ds:bios_data
  230.               mov bx,buffer_tail            ;get current buffer tail address
  231.               mov dx,bx                     ;transfer it to DX
  232.               add dx,2                      ;calculate next buffer position
  233.               cmp dx,buffer_end             ;did we overshoot the end?
  234.               jne insert1                   ;no, then continue
  235.               mov dx,buffer_start           ;yes, then wrap around
  236. insert1:      cmp dx,buffer_head            ;is the buffer full?
  237.               je insert2                    ;yes, then branch
  238.               mov [bx],ax                   ;deposit character into buffer
  239.               mov bx,dx                     ;advance buffer tail
  240.               mov buffer_tail,bx            ;record its new value
  241. insert2:      pop ds                        ;restore DS
  242.               assume ds:nothing
  243.               pop dx                        ;restore DX
  244.               ret                           ;exit
  245. insert_char   endp
  246. ;
  247. ;------------------------------------------------------------------------------
  248. ;KB_DISPLAY opens a window showing all possible key definitions.
  249. ;------------------------------------------------------------------------------
  250. kb_display    proc near
  251. ;
  252. ;Make sure current video mode is an 80-column text mode.
  253. ;
  254.               mov ah,15                     ;get current video mode
  255.               int 10h
  256.               cmp al,2                      ;video mode 2?
  257.               je kb1                        ;yes, then continue
  258.               cmp al,3                      ;video mode 3?
  259.               je kb1                        ;yes, then continue
  260.               cmp al,7                      ;video mode 7 (monochrome)?
  261.               je kb1
  262.               ret                           ;unsupported mode - terminate
  263. kb1:          mov window_status,1           ;set status flag
  264.               push cx                       ;save register values
  265.               push dx
  266.               push si
  267.               push di
  268.               push ds
  269.               push es
  270.               push cs                       ;set DS and ES to the code segment
  271.               pop ds
  272.               assume ds:code
  273.               push cs
  274.               pop es
  275. ;
  276. ;Save page number, cursor mode, and cursor position.  Then blank the cursor.
  277. ;
  278.               mov video_page,bh             ;store video page number
  279.               mov ah,3                      ;get current cursor mode
  280.               int 10h
  281.               mov cursor_mode,cx            ;store cursor mode
  282.               call read_cursor              ;get cursor position
  283.               mov cursor_position,ax        ;save it
  284.               mov ah,1                      ;hide the cursor
  285.               mov ch,20h
  286.               int 10h
  287. ;
  288. ;Save the portion of video memory that will be overwritten.
  289. ;
  290.               cmp adapter,1                 ;disable video if this is a CGA
  291.               jne kb2
  292.               call disable_cga
  293. kb2:          call save_screen              ;copy video memory into buffer
  294. ;
  295. ;Open the keyboard display window.
  296. ;
  297.               call open_window              ;open the window
  298.               cmp adapter,1                 ;enable CGA video
  299.               jne kb3
  300.               call enable_cga
  301. kb3:          lea si,def_table              ;point SI to default key table
  302.               call fill_window              ;draw unshifted key definitions
  303. ;
  304. ;The window is open.  Loop until the ESC key is pressed, continually monitoring
  305. ;the auxiliary shift byte to determine what key definition set to display.
  306. ;
  307. kb4:          mov ah,1                      ;check buffer for character
  308.               int 16h
  309.               jz kb5                        ;branch if buffer is empty
  310.               mov ah,0                      ;get the character
  311.               int 16h
  312.               cmp al,27                     ;is it the ESC key?
  313.               je kb7                        ;yes, then close window and exit
  314. kb5:          mov al,aux_shift              ;get auxiliary shift byte
  315.               cmp al,2                      ;is it <= 2?
  316.               jna kb6                       ;yes, then branch
  317.               mov al,2                      ;no, then set it to 2
  318. kb6:          cmp al,old_shift              ;has the shift status changed?
  319.               je kb4                        ;no, then loop back
  320.               mov old_shift,al              ;record current shift status
  321.               mov bl,83                     ;calculate table address from AL
  322.               mul bl
  323.               mov si,ax                     ;transfer it to SI
  324.               add si,offset def_table       ;complete offset address in SI
  325.               call fill_window              ;write key equivalents to window
  326.               jmp kb4                       ;go back for more
  327. ;
  328. ;The ESC key was pressed.  Close the window and exit.
  329. ;
  330. kb7:          cmp adapter,1                 ;blank CGA video
  331.               jne kb8
  332.               call disable_cga
  333. kb8:          call restore_screen           ;restore contents of video memory
  334.               cmp adapter,1                 ;enable CGA video
  335.               jne kb9
  336.               call enable_cga
  337. kb9:          mov ah,2                      ;restore cursor position
  338.               mov bh,video_page
  339.               mov dx,cursor_position
  340.               int 10h
  341.               mov ah,1                      ;unblank the cursor
  342.               mov cx,cursor_mode
  343.               int 10h
  344.               mov window_status,0           ;reset status flag
  345.               pop es                        ;restore register values
  346.               pop ds
  347.               pop di
  348.               pop si
  349.               pop dx
  350.               pop cx
  351.               ret                          ;return to calling routine
  352. kb_display    endp
  353. ;
  354. ;------------------------------------------------------------------------------
  355. ;SAVE_SCREEN saves the block of video memory that will be overwritten.
  356. ;------------------------------------------------------------------------------
  357. save_screen   proc near
  358.               mov si,182                    ;set zero page window offset in SI
  359.               mov cl,video_page             ;get video page in CX
  360.               xor ch,ch
  361.               jcxz save2                    ;branch if page zero
  362. save1:        add si,1000h                  ;add one page length
  363.               loop save1                    ;loop until offset is correct
  364. save2:        mov video_offset,si           ;save starting window address
  365.               push ds                       ;save DS
  366.               mov ds,video_segment          ;point DS to video memory
  367.               assume ds:nothing
  368.               mov di,screen_buffer          ;point ES:DI to screen buffer
  369.               mov cx,11                     ;11 lines to save
  370. save3:        push cx                       ;save line counter
  371.               mov cx,58                     ;58 characters per line
  372.               cld                           ;clear DF
  373.               rep movsw                     ;transfer one line to storage
  374.               pop cx                        ;retrieve counter
  375.               add si,44                     ;point SI to next line
  376.               loop save3                    ;loop until all lines are saved
  377.               pop ds                        ;restore DS
  378.               assume ds:code
  379.               ret
  380. save_screen   endp
  381. ;
  382. ;------------------------------------------------------------------------------
  383. ;RESTORE_SCREEN restores saved video memory.
  384. ;------------------------------------------------------------------------------
  385. restore_screen proc near
  386.               mov es,video_segment          ;point ES to video segment
  387.               mov di,video_offset           ;point DI to window area
  388.               mov si,screen_buffer          ;point DS:SI to screen buffer
  389.               mov cx,11                     ;11 lines to restore
  390. restore1:     push cx                       ;save line count
  391.               mov cx,58                     ;58 characters per line
  392.               rep movsw                     ;restore one line
  393.               pop cx                        ;retrieve count
  394.               add di,44                     ;advance DI to next line
  395.               loop restore1                 ;loop until done
  396.               ret
  397. restore_screen endp
  398. ;
  399. ;------------------------------------------------------------------------------
  400. ;DISABLE_CGA and ENABLE_CGA control CGA video output.
  401. ;------------------------------------------------------------------------------
  402. disable_cga   proc near
  403.               mov dx,3DAh                   ;Status Register port address
  404. disable1:     in al,dx                      ;read status
  405.               test al,8                     ;vertical retrace active?
  406.               jz disable1                   ;no, then wait until it is
  407.               sub dx,2                      ;point DX to MSR
  408.               mov al,25h                    ;load disable value
  409.               out dx,al                     ;disable video
  410.               ret
  411. disable_cga   endp
  412. ;
  413. enable_cga    proc near
  414.               mov ah,15                     ;get current video mode
  415.               int 10h
  416.               lea bx,enable_values          ;point BX to table of values
  417.               xlat enable_values            ;get value to enable signal
  418.               mov dx,3D8h                   ;MSR address
  419.               out dx,al                     ;enable video output
  420.               ret
  421. enable_cga    endp
  422. ;
  423. ;------------------------------------------------------------------------------
  424. ;READ_CURSOR reads the cursor position directly from the CRT Controller.
  425. ;Exit:  AH,AL - row, column
  426. ;------------------------------------------------------------------------------
  427. read_cursor   proc near
  428.               mov dx,addr_6845              ;get CRTC Address Register port
  429.               mov al,14                     ;specify register number
  430.               out dx,al
  431.               inc dx                        ;point DX to Data Register
  432.               in al,dx                      ;read high byte of cursor address
  433.               mov ah,al                     ;save it in AH
  434.               dec dx                        ;point DX back to Address Register
  435.               mov al,15                     ;specify next register number
  436.               out dx,al
  437.               inc dx                        ;point DX to Data Register
  438.               in al,dx                      ;read low byte of address
  439.               and ax,07FFh                  ;strip page bits from address
  440.               mov bl,80                     ;divide by 80
  441.               div bl
  442.               xchg ah,al                    ;swap AH and AL
  443.               ret
  444. read_cursor   endp
  445. ;
  446. ;------------------------------------------------------------------------------
  447. ;OPEN_WINDOW writes the new window to video memory.
  448. ;------------------------------------------------------------------------------
  449. open_window   proc near
  450.               mov es,video_segment          ;point ES to video memory
  451.               mov di,video_offset           ;point DI to start of window
  452.               mov al,218                    ;get first character code
  453.               mov ah,border_attr            ;and first attribute byte
  454.               stosw                         ;write
  455.               mov cx,56                     ;do the next 56 characters
  456.               mov al,196
  457.               rep stosw
  458.               mov al,191                    ;finish the first line
  459.               stosw
  460.               add di,44                     ;advance DI to next line
  461.               mov cx,9                      ;9 identical lines next
  462. open1:        push cx                       ;save line counter
  463.               mov al,179                    ;do first character
  464.               push ax                       ;save character/attribute
  465.               stosw
  466.               mov cx,56                     ;do the next 56 characters
  467.               mov al,32
  468.               mov ah,text_attr
  469.               rep stosw
  470.               pop ax                        ;retrieve character/attribute pair
  471.               stosw                         ;finish the line
  472.               add di,44                     ;advance DI to next line
  473.               pop cx                        ;retrieve line count
  474.               loop open1                    ;loop until all 9 are done
  475.               mov al,192                    ;first character on last line
  476.               stosw
  477.               mov cx,56                     ;do the next 56
  478.               mov al,196
  479.               rep stosw
  480.               mov al,217                    ;finish the last line
  481.               stosw
  482.               ret
  483. open_window   endp
  484. ;
  485. ;------------------------------------------------------------------------------
  486. ;FILL_WINDOW writes a set of key definitions to the open window.
  487. ;Entry:  DS:SI - key definition table address
  488. ;------------------------------------------------------------------------------
  489. fill_window   proc near
  490.               mov bh,video_page             ;retrieve video page number
  491.               lea di,fill_parms             ;point DI to parameter table
  492.               mov cx,7                      ;7 lines to write
  493. fill1:        push cx                       ;save counter
  494.               add si,word ptr [di]          ;adjust table index
  495.               mov dx,[di+2]                 ;set starting cursor position
  496.               mov cx,[di+4]                 ;set number of characters
  497.               call writeln                  ;write one line
  498.               add di,6                      ;advance parameter table index
  499.               pop cx                        ;retrieve count
  500.               loop fill1                    ;loop until done
  501.               ret
  502. fill_window   endp
  503. ;
  504. ;------------------------------------------------------------------------------
  505. ;WRITELN writes one line of key equivalents to the open window.
  506. ;Entry:  DS:SI - character string address
  507. ;        BH    - video page
  508. ;        CX    - number of characters
  509. ;        DH,DL - starting row and column
  510. ;------------------------------------------------------------------------------
  511. writeln       proc near
  512.               push cx                       ;save character counter
  513.               mov ah,2                      ;position the cursor
  514.               int 10h
  515.               lodsb                         ;get one character
  516.               mov ah,10                     ;print it
  517.               mov cx,1
  518.               int 10h
  519.               add dl,3                      ;advance cursor position
  520.               pop cx                        ;retrieve count
  521.               loop writeln                  ;loop until done
  522.               ret
  523. writeln       endp
  524. ;
  525. ;------------------------------------------------------------------------------
  526. ;INITIALIZE prepares the body of the program for residency.
  527. ;------------------------------------------------------------------------------
  528. initialize    proc near
  529. ;
  530. ;See if the display adapter is an EGA.
  531. ;
  532.               mov ax,0C000h                 ;set ES to EGA BIOS segment
  533.               mov es,ax
  534.               mov di,1Eh                    ;point DI to signature location
  535.               lea si,ibm                    ;point SI to 'IBM' text
  536.               mov cx,3                      ;three bytes to compare
  537.               cld                           ;clear DF
  538.               repe cmpsb                    ;check three bytes
  539.               je init1                      ;branch if signature found
  540. ;
  541. ;Determine whether adapter is a CGA or an MDA.
  542. ;
  543.               dec adapter                   ;decrement assumed value
  544.               mov ah,15                     ;get current video mode
  545.               int 10h
  546.               cmp al,7                      ;is it mode 7?
  547.               jne init1                     ;no, then it's a CGA
  548. ;
  549. ;The display adapter is an MDA.  Modify video attributes.
  550. ;
  551.               dec adapter                   ;set ADAPTER value for MDA
  552.               sub video_segment, 800h       ;modify video segment value
  553.               mov border_attr,70h           ;modify border attribute
  554.               mov text_attr,07h             ;modify text attribute
  555.               mov cursor_mode,0C0Dh         ;modify default cursor shape
  556. ;
  557. ;Reset the cursor to its default shape.
  558. ;
  559. init1:        mov cx,cursor_mode            ;set scan lines in CX
  560.               mov ah,1                      ;video function - set cursor
  561.               int 10h                       ;reset cursor
  562. ;
  563. ;Get and save the address of the CRT Controller.
  564. ;
  565.               mov ax,40h                    ;point ES to BIOS data area
  566.               mov es,ax
  567.               mov di,63h                    ;point DI to address word
  568.               mov dx,es:[di]                ;get CRTC address
  569.               mov addr_6845,dx              ;save it
  570. ;
  571. ;Save the old interrupt 9 vector and replace it with a new one.
  572. ;
  573.               mov ax,3509h                  ;get current interrupt 9 vector
  574.               int 21h
  575.               mov old9h_vector,bx           ;save it
  576.               mov old9h_vector[2],es
  577.               mov ah,25h                    ;then point it to NEW9H routine
  578.               lea dx,new9h
  579.               int 21h
  580. ;
  581. ;Terminate, leaving additional room for screen buffering.
  582. ;
  583.               mov dx,offset initialize+1276 ;set DX for exit
  584.               int 27h                       ;terminate-but-stay-resident
  585. initialize    endp
  586. ;
  587. code          ends
  588.               end begin
  589.